package com.qkun.library.utils;

import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;

import com.qkun.library.BuildConfig;

/**
 * My log utils
 *
 * <p>If the tag is empty for
 * {@link #v(String, String)},{@link #d(String, String)},
 * {@link #i(String, String)},{@link #w(String, String)},
 * {@link #e(String, String)},{@link #a(String, String)},
 * it will be class name.</p>
 *
 * <p>The log format is "className#methodName(lineNumber) { message }"</p>
 *
 * <p>
 * 在主module的build.gradle中需要用下面的方式对library进行依赖，否则<code>BuildConfig.DEBUG</code>会一直是false
 * <p>
 * //省略其余配置
 * ......
 * ......
 * <p>
 * dependencies {
 * <p>
 * //省略其余依赖
 * .....
 * .....
 * <p>
 * //依赖library
 * releaseCompile project(path: ':library', configuration: 'release')
 * debugCompile project(path: ':library', configuration: 'debug')
 * }
 * </p>
 */
public final class MyLog {

    private static final int A = 0x1;       //000001
    private static final int E = 0x3;       //000011
    private static final int W = 0x7;       //000111
    private static final int I = 0xF;       //001111
    private static final int D = 0x1F;      //011111
    private static final int V = 0x3F;      //111111

    private static final int LOG_LEVEL = (BuildConfig.DEBUG ? V : I);

    private MyLog() {
    }

    public static void v(String message) {
        print(V, null, message);
    }

    public static void v(String message, Throwable tr) {
        v(null, message, tr);
    }

    public static void d(Intent intent) {
        print(D, null, getIntentString(intent));
    }

    public static void d(Intent intent, Throwable tr) {
        d(null, intent, tr);
    }

    public static void d(String message) {
        print(D, null, message);
    }

    public static void d(String message, Throwable tr) {
        d(null, message, tr);
    }

    public static void i(String message) {
        print(I, null, message);
    }

    public static void i(String message, Throwable tr) {
        i(null, message, tr);
    }

    public static void w(String message) {
        print(W, null, message);
    }

    public static void w(String message, Throwable tr) {
        w(null, message, tr);
    }

    public static void e(String message) {
        print(E, null, message);
    }

    public static void e(String message, Throwable tr) {
        e(null, message, tr);
    }

    public static void eTrace(Throwable tr) {
        print(E, null, Log.getStackTraceString(tr));
    }

    public static void e(Throwable tr) {
        e(null, tr);
    }

    public static void a(String message) {
        print(A, null, message);
    }

    public static void a(String message, Throwable tr) {
        a(null, message, tr);
    }

    public static void v(String tag, String message) {
        print(V, tag, message);
    }

    public static void v(String tag, String message, Throwable tr) {
        printTrace(V, tag, message, tr);
    }

    public static void d(String tag, Intent intent) {
        print(D, tag, getIntentString(intent));
    }

    public static void d(String tag, Intent intent, Throwable tr) {
        printTrace(D, tag, getIntentString(intent), tr);
    }

    public static void d(String tag, String message) {
        print(D, tag, message);
    }

    public static void d(String tag, String message, Throwable tr) {
        printTrace(D, tag, message, tr);
    }

    public static void i(String tag, String message) {
        print(I, tag, message);
    }

    public static void i(String tag, String message, Throwable tr) {
        printTrace(I, tag, message, tr);
    }

    public static void w(String tag, String message) {
        print(W, tag, message);
    }

    public static void w(String tag, String message, Throwable tr) {
        printTrace(W, tag, message, tr);
    }

    public static void e(String tag, String message) {
        print(E, tag, message);
    }

    public static void e(String tag, String message, Throwable tr) {
        printTrace(E, tag, message, tr);
    }

    public static void eTrace(String tag, Throwable tr) {
        print(E, tag, Log.getStackTraceString(tr));
    }

    public static void a(String tag, String message) {
        print(A, tag, message);
    }

    public static void a(String tag, String message, Throwable tr) {
        printTrace(A, tag, message, tr);
    }

    private static void print(int type, String tag, String message) {
        if ((type & LOG_LEVEL) == type) {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[4];
            String fileName = stackTraceElement.getFileName();
            String methodName = stackTraceElement.getMethodName();
            int lineNumber = stackTraceElement.getLineNumber();
            if (TextUtils.isEmpty(tag)) tag = stackTraceElement.getClassName();
            message = methodName + "(" + fileName + ":" + lineNumber + ") { " + message + " }";
            switch (type) {
                case D:
                    Log.d(tag, message);
                    break;
                case I:
                    Log.i(tag, message);
                    break;
                case W:
                    Log.w(tag, message);
                    break;
                case E:
                    Log.e(tag, message);
                    break;
                case A:
                    Log.wtf(tag, message);
                    break;
                case V:
                    Log.v(tag, message);
                default:
            }
        }
    }

    private static void printTrace(int type, String tag, String message, Throwable tr) {
        if (((type & LOG_LEVEL) == type) && Utils.nonNull(tr)) {
            if (TextUtils.isEmpty(tag)) {
                tag = tr.getStackTrace()[0].getClassName();
            }
            switch (type) {
                case D:
                    Log.d(tag, message, tr);
                    break;
                case I:
                    Log.i(tag, message, tr);
                    break;
                case W:
                    Log.w(tag, message, tr);
                    break;
                case E:
                    Log.e(tag, message, tr);
                    break;
                case A:
                    Log.wtf(tag, message, tr);
                    break;
                case V:
                    Log.v(tag, message, tr);
                default:
            }
        }
    }

    public static String getIntentString(Intent intent) {
        if (Utils.nonNull(intent)) {
            return Utils.isNull(intent.getExtras()) ? intent.toString()
                    : intent.toString().replace("(has extras)", "extras[" + intent.getExtras() + "]");
        }
        return "Intent is null";
    }

}